using System;
using System.Reflection;
using System.Text;

using Pegasus.Diagnostics;

namespace Pegasus
{
	/// <summary>
	/// Summary description for ExceptionHelper.
	/// </summary>
	public class ExceptionHelper
	{
		/// <summary>
		/// Determines whether the exception is serializable or not.  This method scans not only the 
		/// exception passed in but all inner exceptions as well.
		/// </summary>
		/// <param name="e">The exception to check.</param>
		/// <returns>
		/// 	<c>true</c> if the exception is serializable; otherwise, <c>false</c>.
		/// </returns>
		public static bool IsExceptionSerializable( Exception e )
		{
			ParamCode.AssertNotNull( e, "e" );

			Exception ex = e;
			while( ex != null )
			{
				if( !ex.GetType().IsSerializable )
				{
					return false;
				}

				ex = ex.InnerException;
			}

			return true;
		}

		/// <summary>
		/// Build the exception string by revieing the public the object properties.
		/// For not only this exception but for all inner exceptions as well.
		/// </summary>
		/// <param name="e">The exception to dump.</param>
		/// <returns>String dump of the exception</returns>
		public static string DumpExceptionAll( Exception e )
		{
			// Check Params
			ParamCode.AssertNotNull( e, "e" );

			Exception ex = e;
			StringBuilder ret = new StringBuilder();

			// Loop through all the inner exceptions
			while( ex != null )
			{
				ret.Append( DumpException( e ) );
				ex = ex.InnerException;
			}

			return ret.ToString();
		}

		/// <summary>
		/// Build the exception string by revieing the public the object properties.
		/// </summary>
		/// <param name="e">The exception to dump.</param>
		/// <returns>String dump of the exception</returns>
		public static string DumpException( Exception e )
		{
			// Check Params
			ParamCode.AssertNotNull( e, "e" );

			StringBuilder ret = new StringBuilder();

			// Get the public properties for this exception
			Type type = e.GetType();

			// Get all the public properties for this exception.
			PropertyInfo[] properties = type.GetProperties( BindingFlags.Instance | BindingFlags.Public );
			//DebugCode.AssertNotNull( properties );

			ret.AppendFormat( "{0}\n", type.Name );
			ret.AppendFormat( "  Type: {0}\n", type.FullName );

			if( properties.Length > 0 )
			{
				foreach( PropertyInfo property in properties )
				{
					ret.AppendFormat( "  {0}: {1}\n", property.Name, property.GetValue( e, null ) ); 
				}
			}
			else
			{
				ret.Append( "  No public properties for this exception\n" );
			}

            // Get all the public fields for this exception.
            foreach( FieldInfo field in type.GetFields( BindingFlags.Instance | BindingFlags.Public ) )
            {
                ret.AppendFormat( "  {0}: {1}\n", field.Name, field.GetValue( e ) );
            }
            
            ret.Append( "\n" );
			return ret.ToString();
		}
	}
}
